/*    Copyright 2010 Tobias Marschall
 *
 *    This file is part of MoSDi.
 *
 *    MoSDi is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation, either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    MoSDi is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License
 *    along with MoSDi.  If not, see <http://www.gnu.org/licenses/>.
 */

package mosdi.discovery;

import java.util.Arrays;
import java.util.List;

import mosdi.util.Alphabet;
import mosdi.util.ArrayUtils;
import mosdi.util.LogSpace;

public class EvaluatedPattern implements SolutionCandidate {
	private int[] pattern;
	private ScoreAndPValue[] scores;
	
	public EvaluatedPattern() {
		pattern = null;
		scores = new ScoreAndPValue[0];
	}
	
	public EvaluatedPattern(int[] pattern, int score) {
		this.pattern = pattern;
		scores = new ScoreAndPValue[1];
		scores[0] = new ScoreAndPValue(score);
	}

	public EvaluatedPattern(int[] pattern, int score, double minusLogPValue) {
		this.pattern = pattern;
		scores = new ScoreAndPValue[1];
		scores[0] = new ScoreAndPValue(score, minusLogPValue);
	}

	public EvaluatedPattern(int[] pattern, ScoreAndPValue score) {
		this.pattern = pattern;
		scores = new ScoreAndPValue[1];
		scores[0] = score;
	}

	public EvaluatedPattern(int[] pattern, ScoreAndPValue[] scores) {
		this.pattern = pattern;
		this.scores = scores;
	}
	
	public int[] getPattern() { return pattern; }
	
	public int getScore() {
		if (scores.length!=1) throw new IllegalStateException("There are "+scores.length+" present for this pattern.");
		return scores[0].getScore(); 
	}

	public double getMinusLogPValue() { 
		if (scores.length!=1) throw new IllegalStateException("There are "+scores.length+" present for this pattern.");
		return scores[0].getMinusLogPValue(); 
	}

	public int getScore(int objectiveNumber) {
		return scores[objectiveNumber].getScore(); 
	}

	public double getMinusLogPValue(int objectiveNumber) { 
		return scores[objectiveNumber].getMinusLogPValue(); 
	}
	
	@Override
	public int getObjectiveCount() {
		return scores.length;
	}

	@Override
	public double getObjectiveScore(int objectiveNumber) {
		return scores[objectiveNumber].getMinusLogPValue();
	}

	public void setScore(int objectiveNumber, ScoreAndPValue score) {
		scores[objectiveNumber] = score;
	}
	
	/** Returns true if some objectives have not been evaluated and therefore their
	 *  p-value is NaN. */
	public boolean containsNaNs() {
		for (int i=0; i<scores.length; ++i) {
			if (Double.isNaN(scores[i].getMinusLogPValue())) return true;
		}
		return false;
	}
	
	@Override
	public String toString() {
		StringBuffer sb = new StringBuffer();
		sb.append(String.format(">> %s", Arrays.toString(pattern)));
		for (int i=0; i<scores.length; ++i) {
			sb.append(String.format(" >objective%d> %d %e %s", i, scores[i].getScore(), scores[i].getMinusLogPValue(), LogSpace.toString(-scores[i].getMinusLogPValue())));
		}
		return sb.toString();
	}
	
	/** Produces beautified output compared to toString().
	 * 
	 * @param alphabet Alphabet with respect to which pattern is to be printed.
	 * @param objectives List of objectives used to extract objective names using getName() method.
	 */
	public String toString(Alphabet alphabet, List<ObjectiveFunction> objectives) {
		if (scores.length!=objectives.size()) throw new IllegalArgumentException();
		StringBuffer sb = new StringBuffer();
		sb.append(String.format(">> %s", alphabet.buildString(pattern)));
		for (int i=0; i<objectives.size(); ++i) {
			sb.append(String.format(" >%s> %d %e %s", objectives.get(i).getName(), scores[i].getScore(), scores[i].getMinusLogPValue(), LogSpace.toString(-scores[i].getMinusLogPValue())));
		}
		return sb.toString();
	}

	@Override
	public boolean equals(Object o) {
		if (!(o instanceof EvaluatedPattern)) return false;
		return ArrayUtils.compare(pattern, ((EvaluatedPattern)o).pattern) == 0;
	}

	@Override
	public int compareTo(SolutionCandidate o) {
		if (!(o instanceof EvaluatedPattern)) throw new IllegalArgumentException();
		return ArrayUtils.compare(pattern, ((EvaluatedPattern)o).pattern);
	}

	@Override
	public int hashCode() {
		return Arrays.hashCode(pattern);
	}
	
}
